package load_balance

import (
	"fmt"
	"gin-gateway/example/gateway_demo/otherProxy/zookeeper"
)

// 配置主题
type LoadBalanceConf interface {
	Attach(o Observer) // 绑定方法。 将LoadBalanceConf 绑定到 观察者Observer
	GetLoadBalanceIpConf() []string
	WatchConf()
	UpdateConf(conf []string)
}

type LoadBalanceZkConf struct {
	observers         []Observer // 观察者列表， 即需要通知的列表。每个监控路径都是一个观察者observers
	path              string     // 监测路径
	zkHosts           []string
	IpWeightMap       map[string]string // key=ip , v = weight
	loadBalanceIpList []string          // 负载均衡ip列表
	format            string
}

// 把观察者绑定到需要通知的列表
func (s *LoadBalanceZkConf) Attach(o Observer) {
	s.observers = append(s.observers, o) // 每个监控路径都是一个观察者observers
}

func (s *LoadBalanceZkConf) NotifyAllObservers() {
	for _, obs := range s.observers {
		obs.Update()
	}
}

// 获取负载均衡的配置列表
func (s *LoadBalanceZkConf) GetLoadBalanceIpConf() []string {
	var confList []string
	for _, ip := range s.loadBalanceIpList {
		weight, ok := s.IpWeightMap[ip]
		if !ok {
			weight = "50" //默认weight
		}
		confList = append(confList, fmt.Sprintf(s.format, ip)+","+weight) // {"127.0.0.1,20",}
	}
	return confList
}

// 更新配置时，通知监听者也更新
func (s *LoadBalanceZkConf) UpdateConf(NewConf []string) {
	s.loadBalanceIpList = NewConf
	for _, obs := range s.observers {
		obs.Update()
	}
}

// 更新配置时，通知监听者也更新
func (s *LoadBalanceZkConf) WatchConf() {
	zkManager := zookeeper.NewZkManager(s.zkHosts)
	zkManager.GetConnect()
	fmt.Println("watchConf")
	chanList, chanErr := zkManager.WatchServerListByPath(s.path) // 通过路径 ，拿到最新的负载均衡ip列表
	go func() {
		defer zkManager.Close()
		for {
			select {
			case changeErr := <-chanErr:
				fmt.Println("changeErr", changeErr)
			case changedList := <-chanList:
				fmt.Println("watch node changed")
				s.UpdateConf(changedList)
			}
		}
	}()
}

// 通过zkHosts 拿到 负载均衡 ip列表
func NewLoadBalanceZkConf(format, path string, zkHosts []string, IpWeightMap map[string]string) (*LoadBalanceZkConf, error) {
	zkManager := zookeeper.NewZkManager(zkHosts)
	zkManager.GetConnect()
	defer zkManager.Close()
	zlist, err := zkManager.GetServerListByPath(path)
	if err != nil {
		return nil, err
	}
	mConf := &LoadBalanceZkConf{format: format, loadBalanceIpList: zlist, IpWeightMap: IpWeightMap, zkHosts: zkHosts, path: path}
	mConf.WatchConf()
	return mConf, nil
}

type Observer interface {
	Update()
}

type LoadBalanceObserver struct {
	lbZkConf *LoadBalanceZkConf
}

func (l *LoadBalanceObserver) Update() {
	fmt.Println("Update get conf:", l.lbZkConf.GetLoadBalanceIpConf())
}

func NewLoadBalanceObserver(conf *LoadBalanceZkConf) *LoadBalanceObserver {
	return &LoadBalanceObserver{
		lbZkConf: conf,
	}
}
